package sw6.admin.parser;

import java.util.ArrayList;
import java.util.HashMap;

import sw6.admin.database.DatabaseHelper;
import sw6.admin.parser.containers.BooleanSetting;
import sw6.admin.parser.containers.DoubleSetting;
import sw6.admin.parser.containers.EnumElementSetting;
import sw6.admin.parser.containers.EnumSetting;
import sw6.admin.parser.containers.IntegerSetting;
import sw6.admin.parser.containers.ObjectSetting;
import sw6.admin.parser.containers.StringSetting;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;

/**
 * 
 * @author sw6b
 */
public class UpgradeSettings implements ISettingsParserInjection {

	String appName;
	SQLiteDatabase db;
	
	HashMap<String,IntegerSetting> 	integerSettings 	= new HashMap<String,IntegerSetting>();
	HashMap<String,DoubleSetting> 	doubleSettings 		= new HashMap<String,DoubleSetting>();
	HashMap<String,BooleanSetting> 	booleanSettings 	= new HashMap<String,BooleanSetting>();
	HashMap<String,StringSetting> 	stringSettings 		= new HashMap<String,StringSetting>();
	HashMap<String,ObjectSetting> 	objectSettings 		= new HashMap<String,ObjectSetting>();
	HashMap<String,EnumSetting> 	enumSettings 		= new HashMap<String,EnumSetting>();
	ArrayList<EnumElementSetting> 	enumElementSettings	= new ArrayList<EnumElementSetting>();
	
	Context context;
	
	@Override
	public void init(Context context, String appName) {
		this.context = context;
		this.appName = appName;
		db = new DatabaseHelper(context).getWritableDatabase();
		
		// Loading integers
    	Cursor cur = db.query(
			DatabaseHelper.TBL_INTEGERS,
			new String[] { DatabaseHelper.COL_VAR_NAME, DatabaseHelper.COL_VAR_VALUE, DatabaseHelper.COL_VAR_MIN, DatabaseHelper.COL_VAR_MAX },
			DatabaseHelper.COL_APP_NAME + " = ?", new String[] {appName}, null, null, null);
    	if (cur.getCount() > 0) {
    		while(cur.moveToNext()) {
    			integerSettings.put(cur.getString(0), new IntegerSetting(cur.getString(0), cur.getInt(1), cur.getInt(2), cur.getInt(3)));
    		}
    	}
    	cur.close();
    	
		// Loading doubles
    	cur = db.query(
			DatabaseHelper.TBL_DOUBLES,
			new String[] { DatabaseHelper.COL_VAR_NAME, DatabaseHelper.COL_VAR_VALUE, DatabaseHelper.COL_VAR_MIN, DatabaseHelper.COL_VAR_MAX },
			DatabaseHelper.COL_APP_NAME + " = ?", new String[] {appName}, null, null, null);
    	if (cur.getCount() > 0) {
    		while(cur.moveToNext()) {
    			doubleSettings.put(cur.getString(0), new DoubleSetting(cur.getString(0), cur.getDouble(1), cur.getDouble(2), cur.getDouble(3)));
    		}
    	}
    	cur.close();
    	
		// Loading booleans
    	cur = db.query(
			DatabaseHelper.TBL_BOOLEANS,
			new String[] { DatabaseHelper.COL_VAR_NAME },
			DatabaseHelper.COL_APP_NAME + " = ?", new String[] {appName}, null, null, null);
    	if (cur.getCount() > 0) {
    		while(cur.moveToNext()) {
    			booleanSettings.put(cur.getString(0), new BooleanSetting(cur.getString(0)));
    		}
    	}
    	cur.close();
    	
		// Loading strings
    	cur = db.query(
			DatabaseHelper.TBL_STRINGS,
			new String[] { DatabaseHelper.COL_VAR_NAME, DatabaseHelper.COL_VAR_VALUE, DatabaseHelper.COL_VAR_MIN, DatabaseHelper.COL_VAR_MAX },
			DatabaseHelper.COL_APP_NAME + " = ?", new String[] {appName}, null, null, null);
    	if (cur.getCount() > 0) {
    		while(cur.moveToNext()) {
    			stringSettings.put(cur.getString(0), new StringSetting(cur.getString(0), cur.getString(1), cur.getInt(2), cur.getInt(3)));
    		}
    	}
    	cur.close();
    	
		// Loading objects
    	cur = db.query(
			DatabaseHelper.TBL_OBJECTS,
			new String[] { DatabaseHelper.COL_VAR_NAME, DatabaseHelper.COL_VAR_CLASS },
			DatabaseHelper.COL_APP_NAME + " = ?", new String[] {appName}, null, null, null);
    	if (cur.getCount() > 0) {
    		while(cur.moveToNext()) {
    			objectSettings.put(cur.getString(0), new ObjectSetting(cur.getString(0), cur.getString(1)));
    		}
    	}
    	cur.close();

    	// Loading enum elements
    	cur = db.query(
			DatabaseHelper.TBL_ENUM_ELEMS,
			new String[] { DatabaseHelper.COL_VAR_NAME, DatabaseHelper.COL_VAR_VALUE },
			DatabaseHelper.COL_APP_NAME + " = ?", new String[] {appName}, null, null, null);
    	if (cur.getCount() > 0) {
    		while(cur.moveToNext()) {
    			enumElementSettings.add(new EnumElementSetting(appName, cur.getString(0), cur.getInt(1)));
    		}
    	}
    	cur.close();
    	
    	// Loading enums
    	cur = db.query(
			DatabaseHelper.TBL_ENUMS,
			new String[] { DatabaseHelper.COL_VAR_NAME, DatabaseHelper.COL_VAR_VALUE },
			DatabaseHelper.COL_APP_NAME + " = ?", new String[] {appName}, null, null, null);
    	if (cur.getCount() > 0) {
    		while(cur.moveToNext()) {
    			enumSettings.put(cur.getString(0), new EnumSetting(cur.getString(0), cur.getInt(1)));
    		}
    	}
    	cur.close();
	}

	@Override
	public void handleInteger(String varName, int min, int max, int varValue) {
		IntegerSetting setting = integerSettings.get(varName);
		
		if (setting == null) {
			DatabaseHelper.insertInteger(db, appName, varName, varValue, min, max);
		} else if (setting.min != min || setting.max != max) {
			db.delete(DatabaseHelper.TBL_INTEGERS, 
					  DatabaseHelper.COL_APP_NAME + " = ? AND " + DatabaseHelper.COL_VAR_NAME + " = ?", 
					  new String[] { appName, varName });
			
			if (setting.varValue >= min && setting.varValue <= max) {
				DatabaseHelper.insertInteger(db, appName, varName, setting.varValue, min, max);
			} else {
				DatabaseHelper.insertInteger(db, appName, varName, varValue, min, max);
			}
		}
		
		integerSettings.remove(varName);
	}

	@Override
	public void handleDouble(String varName, double min, double max, double varValue) {
		DoubleSetting setting = doubleSettings.get(varName);
		
		if (setting == null) {
			DatabaseHelper.insertDouble(db, appName, varName, varValue, min, max);
		} else if (setting.min != min || setting.max != max) {
			db.delete(DatabaseHelper.TBL_DOUBLES, 
					  DatabaseHelper.COL_APP_NAME + " = ? AND " + DatabaseHelper.COL_VAR_NAME + " = ?", 
					  new String[] { appName, varName });
			
			if (setting.varValue >= min && setting.varValue <= max) {
				DatabaseHelper.insertDouble(db, appName, varName, setting.varValue, min, max);
			} else {
				DatabaseHelper.insertDouble(db, appName, varName, varValue, min, max);
			}
		}
		
		doubleSettings.remove(varName);
	}

	@Override
	public void handleBoolean(String varName, boolean varValue) {
		BooleanSetting setting = booleanSettings.get(varName);
		
		if (setting == null) {
			DatabaseHelper.insertBoolean(db, appName, varName, varValue);
		}
		
		booleanSettings.remove(varName);
	}

	@Override
	public void handleString(String varName, int min, int max, String varValue) {
		StringSetting setting = stringSettings.get(varName);
		
		if (setting == null) {
			DatabaseHelper.insertString(db, appName, varName, varValue, min, max);
		} else if (setting.min != min || setting.max != max) {
			db.delete(DatabaseHelper.TBL_STRINGS, 
					  DatabaseHelper.COL_APP_NAME + " = ? AND " + DatabaseHelper.COL_VAR_NAME + " = ?", 
					  new String[] { appName, varName });
			
			if (setting.varValue.length() >= min && setting.varValue.length() <= max) {
				DatabaseHelper.insertString(db, appName, varName, setting.varValue, min, max);
			} else {
				DatabaseHelper.insertString(db, appName, varName, varValue, min, max);
			}
		}
		
		stringSettings.remove(varName);
	}

	@Override
	public void handleObject(String varName, String type, byte[] varValue) {
		ObjectSetting setting = objectSettings.get(varName);
		
		if (setting == null) {
			DatabaseHelper.insertObject(db, appName, varName, type, varValue);
		} else if (!setting.type.equals(type)) {
			db.delete(DatabaseHelper.TBL_OBJECTS, 
					  DatabaseHelper.COL_APP_NAME + " = ? AND " + DatabaseHelper.COL_VAR_NAME + " = ?", 
					  new String[] { appName, varName });
			
			DatabaseHelper.insertObject(db, appName, varName, type, varValue);
		}
		
		objectSettings.remove(varName);
	}

	@Override
	public void handleEnumElement(String varName, int varValue) {
		boolean foundElementInDB = false;
		
		for (int i = 0; i < enumElementSettings.size(); i++) {
			EnumElementSetting element = enumElementSettings.get(i);
			
			if (element.appName.equals(appName) && element.varName.equals(varName) && element.varValue == varValue) {
				foundElementInDB = true;
				enumElementSettings.remove(i);
				break;
			}
		}
		
		if (!foundElementInDB) {
			DatabaseHelper.insertEnumElement(db, appName, varName, varValue);
		}
		
	}

	@Override
	public void handleEnum(String varName, int varValue) {
		EnumSetting enumSettingFromXml = enumSettings.get(varName);

		if (enumSettingFromXml != null) {
			for (int i = 0; i < enumElementSettings.size(); i++) {
				EnumElementSetting element = enumElementSettings.get(i);

				if (element.appName.equals(appName) && element.varName.equals(enumSettingFromXml.varName) && element.varValue == enumSettingFromXml.varValue) {
					DatabaseHelper.updateEnum(db, appName, varName, varValue);
				}
			}
		} else {
			DatabaseHelper.insertEnum(db, appName, varName, varValue);
		}
		
		enumSettings.remove(varName);
	}

	@Override
	public void end() {
		for (IntegerSetting setting : integerSettings.values()) {
			db.delete(DatabaseHelper.TBL_INTEGERS, 
					  DatabaseHelper.COL_APP_NAME + " = ? AND " + DatabaseHelper.COL_VAR_NAME + " = ?", 
					  new String[] { appName, setting.varName });
		}
		
		for (DoubleSetting setting : doubleSettings.values()) {
			db.delete(DatabaseHelper.TBL_DOUBLES, 
					  DatabaseHelper.COL_APP_NAME + " = ? AND " + DatabaseHelper.COL_VAR_NAME + " = ?", 
					  new String[] { appName, setting.varName });
		}
		
		for (BooleanSetting setting : booleanSettings.values()) {
			db.delete(DatabaseHelper.TBL_BOOLEANS, 
					  DatabaseHelper.COL_APP_NAME + " = ? AND " + DatabaseHelper.COL_VAR_NAME + " = ?", 
					  new String[] { appName, setting.varName });
		}
		
		for (StringSetting setting : stringSettings.values()) {
			db.delete(DatabaseHelper.TBL_STRINGS, 
					  DatabaseHelper.COL_APP_NAME + " = ? AND " + DatabaseHelper.COL_VAR_NAME + " = ?", 
					  new String[] { appName, setting.varName });
		}
		
		for (ObjectSetting setting : objectSettings.values()) {
			db.delete(DatabaseHelper.TBL_OBJECTS, 
					  DatabaseHelper.COL_APP_NAME + " = ? AND " + DatabaseHelper.COL_VAR_NAME + " = ?", 
					  new String[] { appName, setting.varName });
		}
		
		for (EnumElementSetting setting : enumElementSettings) {
			db.delete(DatabaseHelper.TBL_ENUM_ELEMS, 
					  DatabaseHelper.COL_APP_NAME + " = ? AND " + DatabaseHelper.COL_VAR_NAME + " = ? AND " + DatabaseHelper.COL_VAR_VALUE + " = ?", 
					  new String[] { appName, setting.varName, Integer.toString(setting.varValue) });
		}
		
		// This code should never been necessary because we have a foreign key relation between enumElementSettings and enumSetting.values
//		for (EnumSetting setting : enumSetting.values()) {
//			db.delete(DatabaseHelper.TBL_INTEGERS, 
//					  DatabaseHelper.COL_APP_NAME + " = ? AND " + DatabaseHelper.COL_VAR_NAME + " = ?", 
//					  new String[] { appName, setting.varName });
//		}
		
		db.close();
	}

}
